/*
@STI LICENSE
(C) 2006-2008 Universit�t Innsbruck.

This file is part of myOntology.

myOntologyis free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

myOntologyis distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with myOntology.  If not, see <http://www.gnu.org/licenses/>.

@STI LICENSE */
package model;

import java.net.URLDecoder;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.log4j.Logger;
import org.openrdf.model.URI;

import controller.HelperFunctions;
import controller.elementMapper.Mapper;
import controller.sesameDataConnector.AbstractDataConnector;



/**
 * The element in the arrayList of Element Ranker; it contains an URI and the value to this URI.
 * @author andklo
 *
 */
public class RankedElement {

	// indicated, for which view the element is (for OM, Class, Properties); necessary, because DTP and OP are for Properties
	
	private URI uri;		
	private Double value;
	private URI type;
	private String viewType;
	private java.util.Date lastStandartizationDate;
	private java.util.Date hasVersionDateTime;
	private String label;
	private String comment;
	
	public static Logger logger = Logger.getLogger(RankedElement.class);
	
	public static final Double MINVALUE = 1.0;
	
	public RankedElement( URI uri, URI type ) {	
		init(uri, type);
	}

	public RankedElement(String name,String typeString) {
		URI type=null;
		if (typeString.equals("OntologyModule"))
			type = Vocabulary.ONTOLOGYMODULE;
		else if (typeString.equals("Class"))
			type = Vocabulary.CLASS;
		else if (typeString.equals("Property"))
			type = Vocabulary.DATATYPEPROPERTY;
		name = URLDecoder.decode(name);
		URI uri = AbstractDataConnector.createURI(type, name);
		init(uri,type);
		try {
			String label = Mapper.selectLabel(uri, Vocabulary.ENGLISH);
			String comment = Mapper.selectComment( uri, Vocabulary.ENGLISH);
			setLabel(label);
			setComment(comment);
		} catch (Exception e) {
			
		}
	}
	
	/**
	 * @param uri
	 * @param type
	 */
	private void init(URI uri, URI type) {
		this.uri = uri;
		this.type = type;
		this.value = MINVALUE;
		
		if( this.type!=null ) {			
			
			if( this.type.equals(Vocabulary.ONTOLOGYMODULE) )
				this.viewType = DHTMLConstants.ONTOLOGY_VIEWTYPE;
			else if( this.type.equals(Vocabulary.CLASS) )
				this.viewType = DHTMLConstants.CLASS_VIEWTYPE;
			else if( this.type.equals(Vocabulary.DATATYPEPROPERTY) || this.type.equals(Vocabulary.OBJECTPROPERTY) )
				this.viewType = DHTMLConstants.PROPERTY_VIEWTYPE;
			
			this.LoadElement();
		}
		else {
			logger.warn( "TYPE OF THE URI IS NULL (must not be!)!!! uri: " + uri );
		}
	}
	
	
	public void setValue(double val) {
		this.value= val;
	}
	
	
	/**
	 * Stores the value on harddisk. If the server crashes, the clicked values otherwise got lost.
	 * @return	states if storing was successfully.
	 */
	public boolean StoreElement() {
		boolean ret = true;
		
		try {

			AbstractDataConnector.deleteProperty( this.uri, Vocabulary.RELEVANCY );			
			AbstractDataConnector.insertProperty( this.uri, Vocabulary.RELEVANCY, this.value.toString() );			

			AbstractDataConnector.deleteProperty( this.uri, Vocabulary.LASTSTANDARDISATIONDATE );
			AbstractDataConnector.insertProperty( this.uri, Vocabulary.LASTSTANDARDISATIONDATE, HelperFunctions.convertIntoString( this.lastStandartizationDate.getTime() ) );
		}
		catch( Exception e ) {
			logger.error( "Error during BackupElement(): " + this.toString() + ": " , e );

			ret = false;
		}
		
		return ret;
	}
	
	
	/**
	 * Loads the value from the Backup into the internal ArrayLists.
	 * @return
	 */
	private boolean LoadElement() {
		boolean ret = true;

		try {
			String tmp = AbstractDataConnector.selectLiteralObject( this.uri, Vocabulary.RELEVANCY, null );
			if( tmp!=null ) {
				this.value = new Double( tmp );
				
				if( this.value==null )
					this.value = MINVALUE;
			}
			else
				this.value = MINVALUE;
			

			Date d = Mapper.selectHasVersionDateTime( this.uri );
			
			this.hasVersionDateTime = d;

			tmp = AbstractDataConnector.selectLiteralObject( this.uri, Vocabulary.LASTSTANDARDISATIONDATE, null );
			if( tmp!=null ) {	
				this.lastStandartizationDate = HelperFunctions.convertIntoDate( tmp );
			}
			else
				this.lastStandartizationDate = this.hasVersionDateTime;
			
				
		}
		catch( Exception e ) {
			logger.error( "LoadElement: " , e );
		}
		
		return ret;
	}

	public Double getValue() {
		return value;
	}
	
	public void increaseValue( Double value ) {
		this.value += value;
	}

	public URI getUri() {
		return uri;
	}

	public URI getType() {
		return type;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public java.util.Date getHasVersionDateTime() {
		return hasVersionDateTime;
	}

	public void setHasVersionDateTime(java.util.Date hasVersionDateTime) {
		this.hasVersionDateTime = hasVersionDateTime;
	}

	public java.util.Date getLastStandartizationDate() {
		return lastStandartizationDate;
	}

	public void setLastStandartizationDate(java.util.Date lastStandartizationDate) {
		this.lastStandartizationDate = lastStandartizationDate;
	}
	

	/**
	 * Will standartize the value. Every day the clicks get standartized with a specific value (alpha). If an element was not standardized for a couple of days, so it will get standardized with [alpha to the power of daysdifference].
	 * @param alpha	The value, with which the value will get standartized.
	 * @return	returns false if the element has not to be standartized; true: it was standartized and so the value is changed	
	 */
	public boolean Standardize( Double alpha ) {
		
		boolean ret = false;

		// norm the values (if older than 1 day):
		GregorianCalendar yesterday = ( new GregorianCalendar() );
		yesterday.add( GregorianCalendar.HOUR, -24 );

		if( this.getLastStandartizationDate()==null ) {

			ret = true;
			this.lastStandartizationDate = new GregorianCalendar().getTime();
		}
		else {

			
			long diffStandartization = this.getLastStandartizationDate().getTime() - this.getHasVersionDateTime().getTime();
			long diffStandartizationDays = diffStandartization /(24*60*60*1000);
			
			long diffNow = new GregorianCalendar().getTimeInMillis() - this.getHasVersionDateTime().getTime();
			long diffNowDays = diffNow /(24*60*60*1000);
			
			long diffDays = diffNowDays - diffStandartizationDays;

			
			if( diffDays >= 1 ) {
				
				// el.value = el.value * ( ALPHA ) ^ diff:
				for( int i = 0; i < diffDays && this.value>MINVALUE; i++ ) {
	

					
					this.value = this.value*alpha;
					
					if( this.value==null || this.value<MINVALUE ) {
						
						this.value = MINVALUE;
					}
	

				}
	
				ret = true;
				this.lastStandartizationDate = new GregorianCalendar().getTime();
			}
			
		}
		
		return ret;		
	}


	public String getViewType() {
		return viewType;
	}
}
